package com.szzz.gateway.route;

import com.google.common.collect.Lists;
import com.szzz.gateway.route.entity.FilterEntity;
import com.szzz.gateway.route.entity.PredicateEntity;
import com.szzz.gateway.route.entity.RouteEntity;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 动态路由逻辑
 *
 * @author ZhangYin
 */
@Component
@AllArgsConstructor
public class DefaultDynamicRouting implements DynamicRouting, ApplicationEventPublisherAware {

    private final RouteDefinitionWriter routeDefinitionWriter;

    private final RouteDefinitionLocator routeDefinitionLocator;

    private ApplicationEventPublisher publisher;

    @Override
    @Autowired
    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @Override
    public void add(RouteDefinition routeDefinition) {
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            notifyChanged();
    }

    @Override
    public void refresh(Flux<RouteDefinition> routes) {
        list().subscribe(this::delete);
        routes.subscribe(this::add);
    }

    @Override
    public void delete(RouteDefinition routeDefinition) {
        this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId())).subscribe();
        notifyChanged();
    }

    @Override
    public Flux<RouteDefinition> list() {
        return routeDefinitionLocator.getRouteDefinitions();
    }

    private void notifyChanged() {
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

}
